import os
import time
from concurrent.futures import ProcessPoolExecutor

import pandas as pd

from src.Frame import Frame
from src.Object import Object
from src2.FrameParser import FrameParser


class RankMonitor(Object):
    def __init__(self, dir):
        self.dir_path = dir
        self.files = os.listdir(self.dir_path)
        self.files.sort(key=lambda x: int(x[:-4]))
        self.max_worker = os.cpu_count()
        self.pool = ProcessPoolExecutor(self.max_worker)
        self.results = list()
        self.df_tail = pd.DataFrame()
        self.df_rank = pd.DataFrame()
        self.finish_count = 0

    def run_until_finish(self):
        start = time.time()
        show_progress = True

        paths = [(self.dir_path + "/" + f) for f in self.files]
        size_per_group = int(len(self.files) / self.max_worker)  # drop the remainder.

        group = [paths[x * size_per_group + 0:x * size_per_group + size_per_group] for x in range(self.max_worker)]
        for g in group:
            ret = self.pool.submit(RankMonitor.task, g, show_progress)
            show_progress = False
            self.results.append(ret)
            time.sleep(0.1)
        self.pool.shutdown()

        end = time.time()
        self.print('Elapsed %.2f seconds' % (end - start))

    @staticmethod
    def task(group, progress=False):
        frames = list()
        finished_count = 1

        for file in group:
            if progress:
                print('%.2f%%' % (finished_count / len(group) * 100))
            current_frame = None
            frame_completed = False
            with open(file, 'r') as f:
                lines = f.readlines()
                for line in lines:
                    if len(line) > 0:
                        if current_frame is None:
                            if FrameParser.is_time(line):
                                current_frame = Frame()
                                current_frame.add_time(line.split())
                        else:
                            if FrameParser.is_header(line):
                                current_frame.add_head(line.split())
                            elif FrameParser.is_content(line):
                                if not current_frame.is_content_full():
                                    current_frame.add_content(line.split())
                            elif FrameParser.is_tail(line):
                                current_frame.add_tail(line.split())
                                frame_completed = True
                    elif line == '':
                        break
            finished_count += 1
            if current_frame and frame_completed:
                frames.append(current_frame)

            # self.finish_count += 1
            # self.print('(%d) Finished %04d of %04d  %.2f%%' % (threading.currentThread().ident,
            #                                                    self.finish_count, len(self.files),
            #                                                    self.finish_count / len(self.files) * 100));
        return frames

    def get_info(self):
        frames = list()
        for result in self.results:
            frames += result.result()

        for f in frames:
            self.update_frames(f)

        rank = self.df_rank
        status = self.df_tail
        return {'rank': rank, 'mem': status}

    def update_frames(self, frame):
        # self.current_frame.to_string()
        frame.data_frame.drop_duplicates(subset='cmdline', inplace=True)
        ser_data = frame.data_frame['Uss'].astype(int).tolist()
        ser_index = frame.data_frame['cmdline'].tolist()
        ser = pd.Series(ser_data, index=ser_index, name=frame.current_time)

        self.df_rank = self.df_rank.append(ser)
        self.df_tail = self.df_tail.append(frame.tail_series.astype(int))
